/**
 * FileName: NettyServer
 * Author: Mr.Wang
 * Date: 2025/10/15 15:18
 * Description:
 * History:
 */
package org.test.device.config.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import jakarta.annotation.PreDestroy;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
 * 〈一句话功能简述〉<br>
 * 〈netty服务端〉
 * 接收信息
 * @author Mr.Wang
 * @create 2025/10/15
 * @since 1.0.0
 */
@Slf4j
@Component
@EnableConfigurationProperties(NettyProperties.class)
public class NettyServer {

    @Autowired
    NettyProperties nettyProperties;

    @Resource
    @Qualifier("nettyInitTaskExecutor")
    private TaskExecutor taskExecutor;

    // 事件循环组（boss处理连接，worker处理IO）
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel serverChannel;

    /**
     * 启动Netty服务器
     */
    public void start() {
        // 服务端口（从配置获取）
        int port = nettyProperties.getPort();
        String serverHost=nettyProperties.getServerHost();
        // 从配置获取线程数（默认使用CPU核心数）
        bossGroup = new NioEventLoopGroup(nettyProperties.getBossThreadCount());
        log.info("[NettyServer]Netty服务器启动，Boss线程数：{}", nettyProperties.getBossThreadCount());
        workerGroup = new NioEventLoopGroup(nettyProperties.getWorkerThreadCount());
        log.info("[NettyServer]Netty服务器启动，Worker线程数：{}", nettyProperties.getWorkerThreadCount());
        serverChannel=new NioServerSocketChannel();
        log.info("[NettyServer]Netty服务器启动，监听端口：{}", port);

        try {
            ServerBootstrap bootstrap = new ServerBootstrap()
                    .group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    // 服务器端TCP参数配置
                    .option(ChannelOption.SO_BACKLOG, 128) // 连接队列大小
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, nettyProperties.getConnectTimeout())
                    .childOption(ChannelOption.SO_KEEPALIVE, true) // 保持长连接
                    .childOption(ChannelOption.TCP_NODELAY, true) // 禁用Nagle算法（实时性优先）
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            // 配置通道处理器链（责任链模式）
                            ch.pipeline()
                                    // 1. 解决粘包拆包：基于长度字段的解码器
                                    .addLast(new LengthFieldBasedFrameDecoder(
                                            nettyProperties.getMaxFrameLength(),
                                            0, 4, 0, 4))
                                    // 2. 超时处理器（30秒无读写则关闭连接）
                                    // 客户端50秒发送一次心跳（比服务器超时时间短），30秒未收到心跳则断连
                                    .addLast(new IdleStateHandler(30, 50, 0, TimeUnit.SECONDS))
                                    // 3. 帧编码器：添加长度字段
                                    .addLast(new LengthFieldPrepender(4))
                                    // 4. 字符串编解码器（简化字符串消息处理）
                                    .addLast(new StringDecoder(StandardCharsets.UTF_8))
                                    .addLast(new StringEncoder(StandardCharsets.UTF_8))
                                    // 5. 心跳处理器（处理客户端心跳）
                                    .addLast(new HeartbeatHandler())
                                    // 6. 自定义业务处理器（你的业务逻辑）
                                    .addLast(new ServerHandler(taskExecutor));
                        }
                    });

            // 绑定端口（从配置获取）
            ChannelFuture future = bootstrap.bind(port);
            future.addListener(future1 -> {
                if (future1.isSuccess()) {
                    log.info("[NettyServer]Netty服务器启动成功，地址：{},监听端口：{}", serverHost, port);
                    //当前是 Netty 线程，而非线程池线程
                    log.info("[NettyServer]Netty 自身线程：{} 已开始监听端口", Thread.currentThread().getName());
                } else {
                    log.error("[NettyServer]Netty服务器启动失败，端口：{}", port, future1.cause());
                }
            });
            log.info("[NettyServer]Netty服务器启动中，等待连接...");
        } catch (Exception e) {
            log.error("[NettyServer]Netty服务器启动异常，端口：{}", port, e);
            // 异常时主动关闭线程组
            shutdown();
        }
        // 启动逻辑执行到这里，线程池线程就会退出当前方法，回到线程池
        log.info("[NettyServer]Netty启动方法执行完毕，线程池线程释放：{}", Thread.currentThread().getName());
    }

    /**
     * 关闭服务器（Spring销毁时自动执行）
     */
    @PreDestroy
    public void shutdown() {
        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }
        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }
        log.info("[NettyServer]Netty服务器已优雅关闭");
    }

    // 新增：Spring容器销毁时调用，关闭Netty资源
    @PreDestroy
    public void stop() {
        log.info("[NettyServer]开始关闭Netty服务端资源...");
        try {
            // 关闭服务器通道
            if (serverChannel != null && serverChannel.isOpen()) {
                serverChannel.close().sync();
            }
            // 优雅关闭EventLoopGroup（等待所有线程终止）
            if (workerGroup != null) {
                workerGroup.shutdownGracefully().sync();
            }
            if (bossGroup != null) {
                bossGroup.shutdownGracefully().sync();
            }
            log.info("[NettyServer]Netty服务端资源已全部关闭");
        } catch (InterruptedException e) {
            log.error("[NettyServer]关闭Netty服务端异常", e);
            // 强制中断线程（防止卡住）
            Thread.currentThread().interrupt();
        }
    }

    // 自定义心跳处理器
    private class HeartbeatHandler extends ChannelInboundHandlerAdapter {
        private static final String HEARTBEAT_MSG = "HEARTBEAT"; // 心跳消息内容

        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
            if (evt instanceof IdleStateEvent) {
                IdleStateEvent event = (IdleStateEvent) evt;
                // 检测到“写空闲”（50秒未发送消息），发送心跳
                if (event.state() == IdleState.WRITER_IDLE) {
                    ctx.writeAndFlush(HEARTBEAT_MSG);
                    log.debug("[NettyServer]客户端发送心跳消息");
                }
            }
            super.userEventTriggered(ctx, evt);
        }
    }
}